package com.codi.bus.core.service.organ.impl;

import com.alibaba.fastjson.JSONArray;
import com.codi.base.cache.CacheUtil;
import com.codi.base.exception.BaseAppException;
import com.codi.base.exception.ExceptionHandler;
import com.codi.base.util.*;
import com.codi.bus.constant.FundConst;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.constant.RuleConstant;
import com.codi.bus.core.dao.*;
import com.codi.bus.core.domain.*;
import com.codi.bus.core.resultModel.*;
import com.codi.bus.core.service.*;
import com.codi.bus.core.service.model.*;
import com.codi.bus.core.service.organ.OrganAssetsService;
import com.codi.bus.core.service.organ.OrganProfileService;
import com.codi.bus.core.service.util.CalculateAssetsUtils;
import com.codi.bus.core.service.util.FundUtil;
import com.codi.bus.core.service.util.HundsunUtils;
import com.codi.bus.core.service.util.ModelPopulateUtils;
import com.codi.bus.exception.BaseException;
import com.codi.bus.exception.SystemDBException;
import com.codi.bus.util.LookupUtil;
import com.codi.fcloud.ufx.constant.UrlConstants;
import com.codi.fundData.dao.FundDetailDao;
import com.codi.fundData.domain.FundDetail;
import com.codi.fundData.domain.FundMMYieldPerformance;
import com.codi.fundData.domain.SecurityProduct;
import com.codi.fundData.service.FundMMYieldPerformanceService;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import com.codi.trade.dto.HsShareQueryDto;
import com.codi.trade.dto.ShareDetailQryDto;
import com.codi.trade.service.DividendsQueryService;
import com.codi.trade.service.ShareQueryService;
import com.codi.trade.service.TradeApplyQueryService;
import com.codi.trade.service.TradeConfirmQueryService;
import com.codi.trade.service.portfolio.HsShareDetailQryService;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Created by asus on 2018/5/8.
 */

@Service("organAssetsService")
@Slf4j
public class OrganAssetsServiceImpl implements OrganAssetsService {
    @Resource(name = "userDao")
    private UserDao userDao;

    @Resource(name = "shareQueryService")
    private ShareQueryService shareQueryService;

    @Resource(name = "userBankDao")
    private UserBankDao userBankDao;

    @Resource(name = "tradeApplyQueryService")
    private TradeApplyQueryService tradeApplyQueryService;

    @Resource(name = "fundDetailService")
    private FundDetailService fundDetailService;

    @Resource(name = "tradeConfirmQueryService")
    private TradeConfirmQueryService tradeConfirmQueryService;

    @Resource(name = "lookupDao")
    private LookupDao lookupDao;

    @Autowired
    private HsShareDetailQryService hsShareDetailQryService;


    @Autowired
    private BankService bankService;

    @Autowired
    private FundMMYieldPerformanceService fundMMYieldPerformanceService;

    @Autowired
    private FundDetailDao fundDetailDao;

    @Autowired
    private FundCombinationMappingDao fundCombinationMappingDao;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Resource(name = "dividendsQueryService")
    private DividendsQueryService dividendsQueryService;

    @Autowired
    private LookupService lookupService;

    @Autowired
    private UserService userService;

    @Autowired
    private QueryService queryService;

    @Autowired
    private WalletService walletService;

    @Autowired
    private OrganBankDao organBankDao;

    @Autowired
    private ProfitDao profitDao;

    @Autowired
    private OrganProfileService organProfileService;

    @Autowired
    private AssetsIncomeService assetsIncomeService;


    /**
     * 机构资产查询
     *
     * @param userId
     * @param profileId
     * @return
     * @throws BaseException
     */
    @Override
    public AssetsResult queryOrganAssets(Long userId, Long profileId) throws BaseException {
        try {

            /**
             * Step 0: 验证数据
             */
            // 结果
            AssetsResult result = new AssetsResult();
            // 获取用户
            User user = userDao.getEntity(userId);
            // 获取 交易账号
            List<OrganBank> organBankList = organBankDao.selectUsableByProfileId(profileId);
            List<String> tradeAccountList = new ArrayList<>();
            organBankList.forEach(organBank -> {
                if (!tradeAccountList.contains(organBank.getExternalTradeAccount()) && organBank.getAuditStatus() == 1) {
                    tradeAccountList.add(organBank.getExternalTradeAccount());
                }
            });

            OrganProfile organProfile = organProfileService.getById(profileId);

            // 判断是否已开户
            if (user == null || StringUtil.isEmpty(organProfile.getProfileId().toString())) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
                return result;
            }

            // 获取T+0基金
            List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_ORGAN_BAO);
            /**
             * Step 0-1:查询当前工作日
             */
            // 根据恒生银行编号获取银行名称
            List<Lookup> banklookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);


            //份额明细
            ShareDetailQryDto shareDetailQryDto = ShareDetailQryDto.builder()
                .qry_beginrownum("1")
                .begin_date(DateUtils.formatDate4(new Date()))
                .client_id(organProfile.getExternalClientId())
                .end_date(DateUtils.formatDate4(new Date()))
                .reqry_recordsum_flag("1")
                .request_num(GlobalConstant.MAX_REQUEST_NUM)
                .sort_direction("1")
                .build();
            Map<String, Object> map = hsShareDetailQryService.query(shareDetailQryDto);
            List<Map<String, Object>> list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }
            //普通基金
            List<ShareDetailQryModel> shareDetailQryFundModels = new ArrayList<>();

            //组合
            List<ShareDetailQryModel> shareDetailQryPortfolioModels = null;
            if (organBankList != null) {
                if (organBankList.size() != 0) {
                    for (OrganBank organBank : organBankList) {
                        //累加普通基金  份额明细
                        shareDetailQryFundModels = ModelPopulateUtils.populateOrganShareDetailQryFund(list, organBank);
                    }
                }
            }

            /**
             * 普通基金份额查询  非组合部分
             */
//            Map<String, ShareModel> shareMap = new HashMap<>();
            List<ShareModel> normalShares = null;
            List<Map<String, Object>> listAll = new ArrayList<>();
            if (organBankList != null) {
                if (organBankList.size() != 0) {
                    for (OrganBank organBank : organBankList) {
                        // 查询该用户下的所有非组合基金份额
                        map = shareQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, organBank.getExternalTradeAccount(), "1", "", "", "",
                            organProfile.getExternalClientId(), "", "", null);
                        log.warn("map：{}", map.get(GlobalConstant.KEY_LIST_MAP));

                        list = new ArrayList<>();
                        HundsunUtils.ConvertToList(map, list, result);
                        if (!result.getSuccess()) {
                            return result;
                        }
                        listAll.addAll(list);
                    }
                }
            }
            normalShares = ModelPopulateUtils.populateNormalShare(listAll, banklookups);
            //恒生 按交易账号查询 分红
            List<DividendModel> dividends = getOrganDividend(organProfile, organBankList);

            /**
             * Step 2: 交易记录查询
             */
            // 查出这个用户下所有的未确认的交易记录，传ClientId
            map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "", organProfile.getExternalClientId(), "", "", "", GlobalConstant.TACONFIRM_FLAG_UNCONFIRM, "", "", "", "", "", "", "", "");

            // 查询结果
            list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }
            // populate applys
            ApplyListResult applyListResult = new ApplyListResult();
            List<ApplyModel> applysOld = ModelPopulateUtils.populateApply(list, applyListResult, null, null);
            List<String> applyPortfolioCode = new ArrayList<>();
            List<ApplyModel> applys = new ArrayList<>();
            for (ApplyModel applyModel : applysOld) {
                if (!tradeAccountList.contains(applyModel.getTradeAcco())) {
                    continue;
                }
                applys.add(applyModel);
                if (!Strings.isNullOrEmpty(applyModel.getPortfolioCode()) && !applyPortfolioCode.contains(applyModel.getPortfolioCode())) {
                    applyPortfolioCode.add(applyModel.getPortfolioCode());
                }
            }

            //交易申请查询  用于计算瑞富宝累计收益
            list = new ArrayList<>();
            map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
                organProfile.getExternalClientId(), "", "", "", "", "", "", "", "", "", "", "", "");


            // 查询结果
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }
            // 交易业务名称
            List<Lookup> tradeLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_BUSINAME);
            // 银行名称
            List<Lookup> bankLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
            // populate
            List<ApplyModel> applyModels = ModelPopulateUtils.populateApply2(list, applyListResult, tradeLookups, bankLookups, user.getIsOrg());


            //交易确认  用于计算累计收益
            map = tradeConfirmQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "", organProfile.getExternalClientId(), "", "", "", "", "", "", "", "", "", "", "", "", "", "");

            // 查询结果
            list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }

            // populate
            List<ConfirmModel> confirms = ModelPopulateUtils.populateConfirm(list);


            /**
             * Step 3: 从聚源获取基金信息
             */

            // 从聚源获取基金信息
            List<String> fundCodeList = new ArrayList<String>();
            for (ShareModel shareModel : normalShares) {
                if (!fundCodeList.contains(shareModel.getFundCode())) {
                    fundCodeList.add(shareModel.getFundCode());
                }
            }

            List<FundNetValueResult> fundNetValueList = null;
            boolean gliDataException = false;
            try {
                fundNetValueList = fundDetailService.getFundNetValueByBatch(fundCodeList, DateUtils.addDay(new Date(), -1));
            } catch (Exception ex) {
                ExceptionUtil.logError(log, "queryAssets - fundDetailService - Exception:", ex);
                gliDataException = true;
            }

            // 如果没有找到聚源的，返回错误
            if (gliDataException || fundNetValueList == null) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_SYSTEM);
                result.setErrorCode(ErrorConstant.ERROR_GILDATA_WRONG);
                return result;
            }

            // 获取上一工作日净值
            Map<String, BigDecimal> lastNetValues = new HashedMap();
            for (FundNetValueResult netValueResult :
                fundNetValueList) {
                if (netValueResult != null) {
                    if (!lastNetValues.containsKey(netValueResult.getFundCode())) {
                        BigDecimal lastUnitValue = queryService.getLastUnitValue(netValueResult.getFundCode(), netValueResult.getTradingDay());
                        lastNetValues.put(netValueResult.getFundCode(), lastUnitValue);
                    }
                }
            }


            /**
             * Step 4: 计算出前后15天未确认的快速赎回的份额（如果要精确计算的话，只要算当前工作日以及上一工作日的未T+
             * 1确认的实时成功的快速赎回的份额）
             */
//            Map<String, BigDecimal> fastRedeemShares = getFastRedeemSharesWithInterval(userId, new Date(),
//                GlobalConstant.FAST_REDEEM_INTERVAL_DAYS_AFTER_BEFORE);

            Date beginDate = DateUtils.addDay(new Date(), GlobalConstant.FAST_REDEEM_INTERVAL_DAYS_AFTER_BEFORE * (-1));
            Date endDate = DateUtils.addDay(new Date(), GlobalConstant.FAST_REDEEM_INTERVAL_DAYS_AFTER_BEFORE);

            applyListResult = queryService.queryApplys(userId, beginDate, endDate,
                GlobalConstant.FUND_BUSIN_CODE_T0_FAST_APPLY_SELL, GlobalConstant.TACONFIRM_FLAG_REAL_SUCCESS,
                true);
            if (!applyListResult.getSuccess()) {
                throw new BaseException(applyListResult.getErrorCode(), applyListResult.getErrorMessage());
            }

            //近期快速赎回的份额
            Map<String, BigDecimal> fastRedeemShares = CalculateAssetsUtils.getFastSellShares(applyListResult.getApplys());

            //当日快速赎回份额
            Map<String, BigDecimal> todayFastRedeemShares = CalculateAssetsUtils.getTodayFastSellShares(applyListResult.getApplys());

            /**
             * Step 5: 计算结果值
             */

            AssetPortfolioModel assetPortfolioModel = new AssetPortfolioModel();

            assetPortfolioModel.setPortfolioTodayIncome(BigDecimal.valueOf(0));
            assetPortfolioModel.setPortfolioWorthValue(BigDecimal.valueOf(0));
            assetPortfolioModel.setPortfolioAccumIncome(BigDecimal.valueOf(0));
            assetPortfolioModel.setInTransitAmount(BigDecimal.valueOf(0));
            assetPortfolioModel.setInTransit(false);
            assetPortfolioModel.setInTransitNum(0);
            assetPortfolioModel.setPortfolioNum(0);
            // 计算份额，净值日期， 日收益率，万份收益
            List<AssetFundModel> funds = CalculateAssetsUtils.extractFunds(normalShares, lookups, fundNetValueList);
            // 计算总和值，是否有在途
            // 汇总列表
            List<AssetFundModel> sumOfFunds = new ArrayList<>();
            // 零钱包 - 计算零钱包总资产和零钱包总收益
            // 零钱包资产要减去当前工作日已快速赎回的部分，因为快速赎回的部分当前工作日已经没有日收益
            AssetFundModel wallet = CalculateAssetsUtils.sumOfAsset(funds, applys, lookups, true, fastRedeemShares,
                null, todayFastRedeemShares, shareDetailQryFundModels, dividends, confirms, applyModels);
            sumOfFunds.add(wallet);


            //getAccumIncome(wallet,  mapDividend, incomeModelsWallet);


            /**
             * 非组合基金的计算
             */
            // 排除组合后的基金  应该还是包括T0基金的  这里依旧沿用之前的方法  因为获取份额的恒生接口是同一个 所以没有太大的区别  排除掉组合份额后 就可以使用原方法
            //logger.warn("normalSize:{}", normalShares.size());

            List<AssetFundModel> normalFunds = CalculateAssetsUtils.extractFunds(normalShares, lookups, fundNetValueList);
            AssetFundModel normalFund = CalculateAssetsUtils.sumOfAsset(normalFunds, applys, lookups, false, fastRedeemShares,
                lastNetValues, todayFastRedeemShares, shareDetailQryFundModels, dividends, confirms, applyModels);

            // 总资产
            BigDecimal totalWorthValue = MoneyUtils.add(MoneyUtils.add(wallet.getTotalWorthValue(), normalFund.getTotalWorthValue()), assetPortfolioModel.getPortfolioWorthValue());
            // 总收益
            BigDecimal totalTodayIncome = MoneyUtils.add(MoneyUtils.add(wallet.getTotalTodayIncome(), normalFund.getTotalTodayIncome()), assetPortfolioModel.getPortfolioTodayIncome());
            // 总在途金额
            BigDecimal totalInTransitAmount = MoneyUtils.add(MoneyUtils.add(wallet.getInTransitAmount(), normalFund.getInTransitAmount()), assetPortfolioModel.getInTransitAmount());
            //总累计收益
            BigDecimal totalAccumIncome = MoneyUtils.add(MoneyUtils.add(wallet.getTotalAccumIncome(), normalFund.getTotalAccumIncome()), assetPortfolioModel.getPortfolioAccumIncome());
            //总在途笔数
            Integer totalInTransitNum = wallet.getInTransitNum() + normalFund.getInTransitNum() + assetPortfolioModel.getInTransitNum();

            // 返回结果
            result.setSuccess(true);
            // 零钱包
            result.setWallet(wallet);
            // 基金  非组合
            result.setFund(normalFund);
            // 总资产
            result.setTotalWorthValue(totalWorthValue);
            // 当日收益
            result.setTotalTodayIncome(totalTodayIncome);
            //累计收益
            result.setTotalAccumIncome(totalAccumIncome);
            // 总在途金额
            result.setTotalInTransitAmount(totalInTransitAmount);
            //总在途笔数
            result.setTotalInTransitNum(totalInTransitNum);
            //组合
            result.setPortfolios(assetPortfolioModel);

            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(log, "queryAssets - Exception:", exception);
            throw new SystemDBException("queryAssets Failure!", exception);
        }
    }

    /**
     * 机构瑞富宝资金查询
     *
     * @param userId
     * @return
     * @throws BaseException
     */
    @Override
    public AssetsResult queryOrganWalletAssets(Long userId, Long profileId) throws BaseException {
        try {
            AssetsResult result = new AssetsResult();
            /*
             * Step 0: 验证数据
             */
            // 获取用户
            User user = userDao.getEntity(userId);
            // 获取交易账号
            List<OrganBank> organBankList = organBankDao.selectUsableByProfileId(profileId);
            List<String> tradeAccountList = new ArrayList<>();
            organBankList.forEach(organBank -> {
                if (!tradeAccountList.contains(organBank.getExternalTradeAccount()) && organBank.getAuditStatus() == 1) {
                    tradeAccountList.add(organBank.getExternalTradeAccount());
                }
            });

            OrganProfile organProfile = organProfileService.getById(profileId);

            // 判断是否已开户
            if (user == null || StringUtil.isEmpty(organProfile.getExternalClientId())) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
                return result;
            }
            //获取  企业宝基金
            List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_ORGAN_BAO);
            /*
             * Step 1: 资产查询
             */
            // 查询该用户下的所有份额
            HsShareQueryDto hsShareQueryDto = HsShareQueryDto.builder()
                .request_num(GlobalConstant.MAX_REQUEST_NUM)
                .reqry_recordsum_flag("1")
                .qry_beginrownum(1)
                .sort_direction("1")
                .client_id(organProfile.getExternalClientId())
                .build();
            Map<String, Object> map = shareQueryService.query(hsShareQueryDto);

            // 查询结果
            List<Map<String, Object>> list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }

            // populate
            ShareListResult shareListResult = new ShareListResult();
            List<ShareModel> shares = ModelPopulateUtils.populateShare(list, null, shareListResult);

            //份额明细
            ShareDetailQryDto shareDetailQryDto = ShareDetailQryDto.builder()
                .qry_beginrownum("1")
                .begin_date(DateUtils.formatDate4(new Date()))
                .end_date(DateUtils.formatDate4(new Date()))
                .client_id(organProfile.getExternalClientId())
                .reqry_recordsum_flag("1")
                .request_num(GlobalConstant.MAX_REQUEST_NUM)
                .sort_direction("1")
                .build();
            map = hsShareDetailQryService.query(shareDetailQryDto);
            list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }

            //普通基金
            List<ShareDetailQryModel> shareDetailQryFundModels = new ArrayList<>();

            /*
             * 普通基金份额查询
             */
            if (organBankList.size() != 0) {
                for (OrganBank organBank : organBankList) {
                    //累加普通基金  份额明细
                    shareDetailQryFundModels = ModelPopulateUtils.populateOrganShareDetailQryFund(list, organBank);
                }
            }
            // populate
            List<DividendModel> dividends = getOrganDividend(organProfile, organBankList);


            /*
             * Step 2: 交易记录查询
             */
            // 查出这个用户下所有的未确认的交易记录，传ClientId
            map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "", organProfile.getExternalClientId(), "", "", "", GlobalConstant.TACONFIRM_FLAG_UNCONFIRM, "", "", "", "", "", "", "", "");
            // 查询结果
            list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }
            // populate applys
            ApplyListResult applyListResult = new ApplyListResult();
            List<ApplyModel> applysOld = ModelPopulateUtils.populateApply(list, applyListResult, null, null);
            List<ApplyModel> applys = new ArrayList<>();
            List<String> applyPortfolioCode = new ArrayList<>();

            for (ApplyModel applyModel : applysOld) {
                if (!tradeAccountList.contains(applyModel.getTradeAcco())) {
                    continue;
                }
                applys.add(applyModel);
                if (!Strings.isNullOrEmpty(applyModel.getPortfolioCode()) && !applyPortfolioCode.contains(applyModel.getPortfolioCode())) {
                    applyPortfolioCode.add(applyModel.getPortfolioCode());
                }
            }

            //交易申请查询  用于计算瑞富宝累计收益
            list = new ArrayList<>();
            map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
                organProfile.getExternalClientId(), "", "", "", "", "", "", "", "", "", "", "", "");


            // 查询结果
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }
            // 交易业务名称
            List<Lookup> tradeLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_BUSINAME);
            // 银行名称
            List<Lookup> bankLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
            // populate
            List<ApplyModel> applyModels = ModelPopulateUtils.populateApply2(list, applyListResult, tradeLookups, bankLookups, user.getIsOrg());


            //交易确认
            map = tradeConfirmQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "", organProfile.getExternalClientId(), "", "", "", "", "", "", "", "", "", "", "", "", "", "");
            // 查询结果
            list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }

            // populate
            List<ConfirmModel> confirms = ModelPopulateUtils.populateConfirm(list);



            /*
             * Step 3: 获取T+0基金以及从聚源获取基金信息
             */

            // 从聚源获取基金信息
            List<String> fundCodeList = new ArrayList<>();
            for (ShareModel shareModel : shares) {
                fundCodeList.add(shareModel.getFundCode());
            }

            List<FundNetValueResult> fundNetValueList = null;
            boolean gliDataException = false;
            try {
                fundNetValueList = fundDetailService.getFundNetValueByBatch(fundCodeList, DateUtils.addDay(new Date(), -1));
            } catch (Exception ex) {
                ExceptionUtil.logError(log, "queryAssets - fundDetailService - Exception:", ex);
                gliDataException = true;
            }

            // 如果没有找到聚源的，返回错误
            if (gliDataException || fundNetValueList == null) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_SYSTEM);
                result.setErrorCode(ErrorConstant.ERROR_GILDATA_WRONG);
                return result;
            }

            // 获取上一工作日净值
            Map<String, BigDecimal> lastNetValues = new HashMap<>();
            for (FundNetValueResult netValueResult : fundNetValueList) {
                if (netValueResult != null) {
                    if (!lastNetValues.containsKey(netValueResult.getFundCode())) {
                        BigDecimal lastUnitValue = queryService.getLastUnitValue(netValueResult.getFundCode(), netValueResult.getTradingDay());
                        lastNetValues.put(netValueResult.getFundCode(), lastUnitValue);
                    }
                }
            }
            /*
             * Step 4: 计算出前后15天未确认的快速赎回的份额（如果要精确计算的话，只要算当前工作日以及上一工作日的未T+
             * 1确认的实时成功的快速赎回的份额）
             */
            Date beginDate = DateUtils.addDay(new Date(), GlobalConstant.FAST_REDEEM_INTERVAL_DAYS_AFTER_BEFORE * (-1));
            Date endDate = DateUtils.addDay(new Date(), GlobalConstant.FAST_REDEEM_INTERVAL_DAYS_AFTER_BEFORE);

            applyListResult = queryService.queryApplys(userId, beginDate, endDate,
                GlobalConstant.FUND_BUSIN_CODE_T0_FAST_APPLY_SELL, GlobalConstant.TACONFIRM_FLAG_REAL_SUCCESS,
                true);
            if (!applyListResult.getSuccess()) {
                throw new BaseException(applyListResult.getErrorCode(), applyListResult.getErrorMessage());
            }

            //近期快速赎回的份额
            Map<String, BigDecimal> fastRedeemShares = CalculateAssetsUtils.getFastSellShares(applyListResult.getApplys());

            //当日快速赎回份额
            Map<String, BigDecimal> todayFastRedeemShares = CalculateAssetsUtils.getTodayFastSellShares(applyListResult.getApplys());

            /*
             * Step 5: 计算结果值
             */
            // 计算份额，净值日期， 日收益率，万份收益
            List<AssetFundModel> funds = CalculateAssetsUtils.extractFunds(shares, lookups, fundNetValueList);
            // 零钱包 - 计算零钱包总资产和零钱包总收益
            // 零钱包资产要减去当前工作日已快速赎回的部分，因为快速赎回的部分当前工作日已经没有日收益
            AssetFundModel wallet = CalculateAssetsUtils.sumOfAsset(funds, applys, lookups, true, fastRedeemShares,
                null, todayFastRedeemShares, shareDetailQryFundModels, dividends, confirms, applyModels);

            result.setWallet(wallet);
            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(log, "queryAssets - Exception:", exception);
            throw new SystemDBException("queryAssets Failure!", exception);
        }
    }

    /**
     * @param userId
     * @return
     * @throws BaseAppException
     */
    @Override
    public WalletDetailResultV2 getOrganWallet(Long userId, Long profileId) throws BaseAppException {
        // 校验fundCode是否在T0列表中
        //获取 企业宝基金
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_ORGAN_BAO);
        if (ListUtil.isEmpty(lookups)) {
            log.error("wallet init sql error, please check.");
            ExceptionHandler.publish(ErrorConstant.ERROR_SYS_EXCEPTION);
        }
        WalletDetailResultV2 result = new WalletDetailResultV2();

        // --------------- 和用户相关内容 begin ---------------

        AssetsResult assetsResult = queryOrganWalletAssets(userId, profileId);
        if (!assetsResult.getSuccess()) {
            String errorMsg = MessageUtil.getErrorMessage(assetsResult.getErrorCode(), null);
        } else {
            AssetFundModel wallet = assetsResult.getWallet();
            if (wallet != null) {
                // 零钱
                result.setTotalWorthValue(MoneyUtils.formatMoney(wallet.getTotalWorthValue(), 2));
                // 总当日收益
                result.setTotalTodayIncome(MoneyUtils.formatMoney(wallet.getTotalTodayIncome(), 2));
                //设置总收益
                result.setTotalIncome(MoneyUtils.formatMoney(wallet.getTotalAccumIncome(), 2));
                //设置总在途
                result.setInTransitAmount(wallet.getInTransitAmount());
                //在途笔数
                result.setInTransitNum(wallet.getInTransitNum());
                //设置净值日期
                result.setNetValueDate(wallet.getNetValueDate());
                //设置基金详情的基金姓名
                walletService.setFundName(wallet, lookups);
                result.setFundModelList(wallet.getFundModelList());
            }
        }
        result.setSuccess(true);
        return result;
    }

    @Override
    public WalletDetailResult getOrganWalletDetailByFundCode(Long userId, String fundCode, Long profileId) throws BaseAppException {
        // 校验fundCode是否在T0列表中
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
        if (ListUtil.isEmpty(lookups)) {
            log.error("wallet init sql error, please check.");
            ExceptionHandler.publish(ErrorConstant.ERROR_SYS_EXCEPTION);
        }

        SecurityProduct product = fundDetailService.getSecurityProduct(fundCode);

        WalletDetailResult result = new WalletDetailResult();
        AssetsResult assetsResult = queryOrganWalletAssets(userId, profileId);

        // --------------- 和用户相关内容 begin ---------------
        // 是否有余额
        boolean hasBalance = false;
        User user = userService.getUser(userId);

        //每日最高限额
        if (user != null) {
            walletService.setMaxLimit(result, lookups, fundCode, user.getIsOrg());

            //
            // 宝盈不支持机构快速赎回 // spy 2017-11-3 13:26:44
            if (FundUtil.isBaoYingT0AB(fundCode)) {
                if (user.getIsOrg()) {
                    result.setCanFastRedeem(false);
                }
            }
        }

        AssetFundModel wallet = null;
        if (!assetsResult.getSuccess()) {

        } else {
            wallet = assetsResult.getWallet();
            AssetFundModel hitModel = null;

            if (wallet != null) {
                List<AssetFundModel> list = wallet.getFundModelList();
                walletService.setFundName(wallet, lookups);
                for (AssetFundModel m : list) {
                    Boolean isB = product.getChiNameAbbr().replace("A", "B").equals(m.getFundName());
                    if (fundCode.equals(m.getFundCode()) || isB) {
                        hitModel = m;
                        fundCode = m.getFundCode();
                        break;
                    }
                }
                if (hitModel != null) {
                    result.setTodayIncome(MoneyUtils.formatMoney(hitModel.getTotalTodayIncome()));
                    result.setTotalIncome(MoneyUtils.formatMoney(hitModel.getTotalAccumIncome()));
                    result.setWalletMoney(MoneyUtils.formatMoney(hitModel.getTotalWorthValue()));
                    result.setFundName(hitModel.getFundName());
                    result.setFundCode(hitModel.getFundCode());

                }

            }
        }
        product = fundDetailService.getSecurityProduct(fundCode);

        if (product == null) {
            log.error("Security Product is not exist");
            result.setErrorCode(ErrorConstant.ERROR_FUND_NOT_EXIST);
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
            result.setSuccess(false);
            return result;
        }
        result.setFundName(product.getChiNameAbbr());
        result.setFundCode(fundCode);
        // 七日年化率
        FundMMYieldPerformance perf = fundMMYieldPerformanceService.getFundMMYieldPerformance(product.getInnerCode());
        result.setNetValueDate(perf.getTradingDay());
        result.setLatestWeeklyYield(MoneyUtils.formatMoneyNoRound(perf.getLatestWeeklyYield(), 2));// 最近7日折算年收益率（%）
        result.setDailyProfit(MoneyUtils.formatMoney(perf.getDailyProfit(), 4));

        // 最近七天的七日年化收益率(降序)
        walletService.setWeekYield(product, result);
        walletService.setSellAndBuy(hasBalance, fundCode, wallet, result);
        result.setSuccess(true);
        return result;
    }

    @Override
    public CashChangeListResult getWalletCashChangeDetails(Long userId, String fundCode, Long profileId) {
        log.info("userId={},fundCode={}", userId, fundCode);

        // T0 Funds 基金
        List<Lookup> lookups = lookupService.getLookups(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
        ShareListResult shareListResult = null;
        CashChangeListResult cashChangeListResult = new CashChangeListResult();
        Map<String, TradeLimitModel> tradeLimitModels = new HashMap<>();
        List<CashChangeResult> cashChangeResults = new ArrayList<>();

        Preconditions.checkNotNull(lookups, "T0数据为空请检查");

        User user = userService.getUser(userId);
        List<OrganBank> organBankList = organBankDao.selectUsableByProfileId(profileId);

        List<String> tradeAccountList = new ArrayList<>();
        organBankList.forEach(organBank -> {
            if (!tradeAccountList.contains(organBank.getExternalTradeAccount()) && organBank.getAuditStatus() == 1) {
                tradeAccountList.add(organBank.getExternalTradeAccount());
            }
        });

        String custType = user.getIsOrg() ? GlobalConstant.CUST_TYPE_ORGANIZATION : GlobalConstant.CUST_TYPE_PERSONAL;

        List<Lookup> epayLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_EPAYBANK);

        String brandsType = FundUtil.getT0FundBrandsType(fundCode);

        for (Lookup lookup : lookups) {
            if (EqualsUtil.equals(lookup.getRuleValue(), fundCode.trim())) {

                shareListResult = walletService.queryOrganShareModels(profileId, lookup.getRuleValue());

                if (false == shareListResult.getSuccess()) {
                    cashChangeListResult.setSuccess(false);
                    cashChangeListResult.setErrorCode(shareListResult.getErrorCode());
                    cashChangeListResult.setErrorType(shareListResult.getErrorType());
                    return cashChangeListResult;
                }
                List<ShareModel> models = shareListResult.getShares();
                log.info("models.size={}", models.size());
                for (ShareModel model : models) {
                    if (!tradeAccountList.contains(model.getTradeAccount())) {
                        continue;
                    }
                    if (model.getCurrentShare().compareTo(BigDecimal.valueOf(0)) == 0) {
                        continue;
                    }
                    CashChangeResult cashChangeResult = new CashChangeResult();
                    List<OrganBank> organBanks = organBankDao.selectByTradeAccount(model.getTradeAccount());
                    OrganBank userBankForBranch = new OrganBank();
                    if (organBanks != null && !organBanks.isEmpty()) {
                        userBankForBranch = organBanks.get(0);
                        model.setBranchBank(userBankForBranch.getUbBranchbank() == null ? "" : userBankForBranch.getUbBranchbank());
                        model.setBranchBankName(userBankForBranch.getUbBankBranchName() == null ? "" : userBankForBranch.getUbBankBranchName());
                    }
                    cashChangeResult.setBankName(model.getBankName());
                    cashChangeResult.setBankAccount(model.getBankAccount());
                    cashChangeResult.setEnableShare(model.getEnableShares());
                    cashChangeResult.setTradeAccount(model.getTradeAccount());
                    cashChangeResult.setCapitalMode(model.getCapitalMode());
                    cashChangeResult.setFundCode(lookup.getRuleValue());
                    for (Lookup epayLookup : epayLookups) {
                        if (model.getBankName().equals(epayLookup.getRuleText())) {
                            cashChangeResult.setBankCode(epayLookup.getRuleValue());
                        }
                    }
                    TradeLimitModel tradeLimitModel;
                    /**
                     * 赎回限额
                     */
                    String fastSellKey = lookup.getRuleValue() + model.getShareType() + model.getCapitalMode()
                        + GlobalConstant.FUND_BUSIN_CODE_APPLY_SELL;
                    if (tradeLimitModels.get(fastSellKey) == null) {
                        tradeLimitModel = queryService.getTradeLimit(lookup.getRuleValue(),
                            GlobalConstant.FUND_BUSIN_CODE_APPLY_SELL, model.getShareType(),
                            custType,
                            model.getCapitalMode());

                        tradeLimitModels.put(fastSellKey, tradeLimitModel);
                    } else {
                        tradeLimitModel = tradeLimitModels.get(fastSellKey);
                    }

                    if (tradeLimitModel != null) {
                        cashChangeResult.setMinValue(tradeLimitModel.getMinValue());
                        cashChangeResult.setMinHoldShares(tradeLimitModel.getMinHoldShares());
                        cashChangeResult.setMaxValueForSell(tradeLimitModel.getMaxValue());
                    } else {
                        // 如果未找到，则不返回，前端根据是否有返回来决定是否做验证限制
                        log.warn("sell tradeLimitModel does not exist");
                    }
                    // 设置最高可快速赎回的金额
                    // 如果为空，则不返回，前端根据是否有返回来决定是否做验证限制
                    if (!StringUtil.isEmpty(lookup.getComponentValue())) {
                        String str = lookup.getComponentValue();

                        String maxLimit = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(), RuleConstant.FIELD_DAY_LIMIT);

                        // 如果转换出错，则默认为最大值，让交易成功提交，由直销系统做最后的限制
                        cashChangeResult.setMaxValueForFastSell(BigDecimalUtil
                            .ConvertToBigDecimal(maxLimit, new BigDecimal(Integer.MAX_VALUE)));
                    }
                    //TODO 这里结构设计有问题,先保持原先结构  spy 2017-11-1
                    String str = lookup.getComponentValue();
                    if (FundUtil.isBaoYingT0AB(fundCode)) {
                        Lookup tmpLookup = lookupService.getLookup(RuleConstant.T0FUND_BAOYING_CONFIG);
                        str = tmpLookup.getComponentValue();
                    }

                    if (StringUtil.isNotEmpty(str) && LookupUtil.isJSONObject(str)) {

                        String dayDealLimitStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(), RuleConstant.FIELD_DAY_LIMIT);
                        String singleDealLimitStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(), RuleConstant.FIELD_SINGLE_DEAL_LIMIT);
                        String totalCountStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(), RuleConstant.FIELD_DAY_DEAL_COUNT_LIMIT);

                        // 单日交易限制
                        BigDecimal dayDealMaxValue = BigDecimalUtil.ConvertToBigDecimal(dayDealLimitStr);
                        cashChangeResult.setFastRedeemDayDealMaxValue(BigDecimalUtil.ConvertToBigDecimal(dayDealLimitStr));

                        // 剩余单日额度 spy 2017-11-3 10:56:05
                        if (EqualsUtil.equals("-1", dayDealLimitStr)) {
                        } else {
                            BigDecimal usedMoney = walletService.getFastRedeemDayUsedMoney(userId, brandsType);
                            BigDecimal finalValue = MoneyUtils.max(dayDealMaxValue.subtract(usedMoney), BigDecimal.ZERO);
                            cashChangeResult.setFastRedeemRetainDayDealMaxValue(finalValue);
                        }

                        // 单笔交易限额
                        cashChangeResult.setFastRedeemSingleDealMaxValue(BigDecimalUtil.ConvertToBigDecimal(singleDealLimitStr));

                        // 可交易总次数
                        int totalCount = Integer.valueOf(totalCountStr);
                        cashChangeResult.setFastRedeemTotalCountPerDay(Integer.valueOf(totalCountStr));

                        // 可交易剩余次数(总次数-已用次数)
                        if (EqualsUtil.equals("-1", totalCountStr)) {
                        } else {
                            int count = Math.max(totalCount - walletService.getFastRedeemCountInCurrentDay(userId, brandsType), 0);
                            cashChangeResult.setFastRedeemRetainCountPerDay(count);
                        }
                        switch (cashChangeResult.getFundCode()) {
                            case GlobalConstant.T0_FUND_JINYING_A:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("未结转收益可于每月15日赎回");
                                break;
                            case GlobalConstant.T0_FUND_JINYING_B:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("未结转收益可于每月15日赎回");
                                break;
                            case GlobalConstant.T0_FUND_CHANGCHENG_A:
                                cashChangeResult.setFastRedeemTime("快速取现时间为：每个工作日9:00-16:45");
                                cashChangeResult.setWalletString("未结转收益可于每月15日赎回");
                                break;
                            case GlobalConstant.T0_FUND_CHANGCHENG_B:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("未结转收益可于每月15日赎回");
                                break;
                            case GlobalConstant.T0_FUND_BAOYING_A:
                                cashChangeResult.setWalletString("未结转收益可于每月5日赎回");
                                cashChangeResult.setFastRedeemTime("");
                                break;
                            case GlobalConstant.T0_FUND_BAOYING_B:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("未结转收益可于每月5日赎回");
                                break;
                            case GlobalConstant.T0_FUND_JINYING2_A:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("每日结转当期收益");
                                break;
                            case GlobalConstant.T0_FUND_JINYING2_B:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("每日结转当期收益");
                                break;
                            case GlobalConstant.T0_FUND_CHANGCHENG_E:
                                cashChangeResult.setFastRedeemTime("快速取现时间为：每个工作日9:00-16:45");
                                cashChangeResult.setWalletString("每日结转当期收益");
                                break;
                            default:
                                break;
                        }
                    }

                    cashChangeResults.add(cashChangeResult);
                }
                cashChangeListResult.setCashChangeResults(cashChangeResults);
            }
        }
        return cashChangeListResult;
    }


    @Override
    public ShareListResult queryOrganSharesWithoutPort(Long userId, Integer requestNum, Integer queryflag, Integer beginNum,
                                                       String sortDirection, boolean filterT0, Long profileId) throws BaseException {
        log.info("queryShares - userId=" + userId);

        ShareListResult result = new ShareListResult();
        try {
            // 获取T+0基金
            List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_ORGAN_BAO);
            // Step 1: 获取用户
            User user = userDao.getEntity(userId);

            List<OrganBank> organBankList = organBankDao.selectUsableByProfileId(profileId);
            List<String> tradeAccountList = new ArrayList<>();
            organBankList.forEach(organBank -> {
                if (!tradeAccountList.contains(organBank.getExternalTradeAccount()) && organBank.getAuditStatus() == 1) {
                    tradeAccountList.add(organBank.getExternalTradeAccount());
                }
            });

            OrganProfile organProfile = organProfileService.getById(profileId);

            // 判断是否已开户
            if (user == null || StringUtil.isEmpty(organProfile.getExternalClientId())) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
                return result;
            }

            // 根据恒生银行编号获取银行名称
            List<Lookup> lookupsBank = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);

            // Step 2: 资产查询, 查询该用户下的所有份额
            Map<String, ShareModel> shareMap = new HashMap<>();
            List<ShareModel> normalShares = new ArrayList<>();
            //分红
            List<DividendModel> dividends = getOrganDividend(organProfile, organBankList);
            List<Map<String, Object>> list = new ArrayList<>();
            if (organBankList != null) {
                if (organBankList.size() != 0) {
                    List<Map<String, Object>> listAll = new ArrayList<>();

                    for (OrganBank organBank : organBankList) {
                        // 查询该用户下的所有非组合基金份额
                        Map<String, Object> map = shareQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, organBank.getExternalTradeAccount(), "1", "", "", "",
                            organProfile.getExternalClientId(), "", "", null);
                        list = new ArrayList<>();
                        HundsunUtils.ConvertToList(map, list, result);
                        if (!result.getSuccess()) {
                            return result;
                        }
                        listAll.addAll(list);
                    }
                    normalShares = ModelPopulateUtils.populateNormalShare(listAll, lookupsBank);
                    for (ShareModel shareModel : normalShares) {
                        //FundModel fundModel = queryService.queryFund(shareModel.getFundCode());
                        shareModel.setFundStatus("0");
                    }

                }
            }
            //份额明细
            ShareDetailQryDto shareDetailQryDto = ShareDetailQryDto.builder()
                .qry_beginrownum("1")
                .begin_date(DateUtils.formatDate4(new Date()))
                .client_id(organProfile.getExternalClientId())
                .end_date(DateUtils.formatDate4(new Date()))
                .reqry_recordsum_flag("1")
                .request_num(GlobalConstant.MAX_REQUEST_NUM)
                .sort_direction("1")
                .build();
            Map<String, Object> map = hsShareDetailQryService.query(shareDetailQryDto);
            list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }

            //普通基金
            List<ShareDetailQryModel> shareDetailQryFundModels = new ArrayList<>();
            if (organBankList != null) {
                if (organBankList.size() != 0) {
                    for (OrganBank organBank : organBankList) {
                        shareDetailQryFundModels = ModelPopulateUtils.populateOrganShareDetailQryFund(list, organBank);
                    }
                }
            }

            // 把T0基金过滤掉，因为T0基金有专门的页面来显示
            if (filterT0) {
                List<Lookup> T0Funds = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_ORGAN_BAO);
                Iterator<ShareModel> iterator = normalShares.iterator();
                while (iterator.hasNext()) {
                    ShareModel model = iterator.next();
                    if (ModelPopulateUtils.isT0Fund(T0Funds, model.getFundCode())) {
                        iterator.remove();
                    }
                }
            }

            // Step 3: 从聚源获取基金信息
            List<String> fundCodeList = new ArrayList<String>();
            for (ShareModel shareModel : normalShares) {
                fundCodeList.add(shareModel.getFundCode());
            }

            List<FundNetValueResult> fundNetValueList = null;
            try {
                Date t = queryService.maxDate();
                fundNetValueList = fundDetailService.getFundNetValueByBatch(fundCodeList, DateUtils.addDay(new Date(), -1));
            } catch (Exception ex) {
                ExceptionUtil.logError(log, "queryShares - fundDetailService - Exception:", ex);
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_SYSTEM);
                result.setErrorCode(ErrorConstant.ERROR_GILDATA_WRONG);
                return result;
            }

            // 如果没有找到聚源的，则默认为空
            if (fundNetValueList == null) {
                fundNetValueList = new ArrayList<>();
            }

            // Step 4: 从恒生获取交易确认信息
            // 入参为交易账号的话，只查询该交易账号下的交易, 如果为客户编号的话，则查询该客户编号下的所有交易账号的交易
            Map<String, Object> confirmMap = tradeConfirmQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1",
                organProfile.getExternalClientId(), "", "");

            // 查询结果
            List<Map<String, Object>> mapList = new ArrayList<>();
            HundsunUtils.ConvertToList(confirmMap, mapList, result);
            if (!result.getSuccess()) {
                return result;
            }


            // populate
            List<ConfirmModel> confirms = ModelPopulateUtils.populateConfirm(mapList);


            /**
             * 交易记录
             */
            // 查出这个用户下所有的未确认的交易记录，传ClientId
            map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
                organProfile.getExternalClientId(), "", "", "", GlobalConstant.TACONFIRM_FLAG_UNCONFIRM, "", "", "", "", "",
                "", "", "");

            // 查询结果
            list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }
            // populate applys
            ApplyListResult applyListResult = new ApplyListResult();
            List<ApplyModel> applysOld = ModelPopulateUtils.populateApply(list, applyListResult, null, null);
            List<ApplyModel> applys = new ArrayList<>();
            // 把T0基金过滤掉，因为T0基金有专门的页面来显示
            queryService.filterOrganBao(applysOld);
            for (ApplyModel applyModel : applysOld) {
                if (!tradeAccountList.contains(applyModel.getTradeAcco())) {
                    continue;
                }
                applys.add(applyModel);
            }

            // Step 5: 根据数据计算
            // 总持仓收益
            BigDecimal totalAccumIncome = new BigDecimal(0);
            log.debug("totalAccumIncome1:{}", totalAccumIncome);

            // 总本金
            BigDecimal totalFundBalance = new BigDecimal(0);
            // 总资产
            BigDecimal totalWorthValue = new BigDecimal(0);
            // 总当日收益
            BigDecimal totalTodayIncome = new BigDecimal(0);
            //总持仓收益
            BigDecimal totalShareIncome = new BigDecimal(0);
            // 保存上一工作日净值
            Map<String, BigDecimal> netValues = new HashedMap();
            // 净值日期
            Date netValueDate = DateUtils.addDay(new Date(), -1); //默认净值日期为前一天

            //基金编码集合
            List<String> fundCodes = new ArrayList<>();

            for (ShareModel shareModel : normalShares) {
                fundCodes.add(shareModel.getFundCode());
                List<OrganBank> organBanks = organBankDao.selectByTradeAccount(shareModel.getTradeAccount());
                OrganBank userBankForBranch = new OrganBank();
                if (organBanks != null && !organBanks.isEmpty()) {
                    userBankForBranch = organBanks.get(0);
                    shareModel.setBranchBank(userBankForBranch.getUbBranchbank() == null ? "" : userBankForBranch.getUbBranchbank());
                    shareModel.setBranchBankName(userBankForBranch.getUbBankBranchName() == null ? "" : userBankForBranch.getUbBankBranchName());
                }

                // 更新基金
                // 设置净值默认值
                shareModel.setNetValue(new BigDecimal(0));
                // 设置今日收益默认值
                shareModel.setTodayIncome(new BigDecimal(0));
                // 设置今日收益率默认值
                shareModel.setTodayIncomeRate(new BigDecimal(0));
                // 设置基金信息
                for (FundNetValueResult fundNetValue : fundNetValueList) {
                    // 聚源没有找到该只基金
                    if (fundNetValue == null || StringUtil.isEmpty(fundNetValue.getFundCode()) || fundNetValue.getFundTypeCode() == null) {
                        continue;
                    }
                    // 以聚源的数据为准
                    if (fundNetValue.getFundCode().equals(shareModel.getFundCode())) {
                        shareModel.setFundName(fundNetValue.getChiNameAbbr());
                        shareModel.setNetValue(fundNetValue.getUnitNV());
                        shareModel.setNetValueDate(fundNetValue.getTradingDay());
                        netValueDate = fundNetValue.getTradingDay();
                        // 设置前端显示的基金类型
                        shareModel.setAppFundType(fundNetValue.getFundTypeCode());
                        if (fundNetValue.getFundTypeCode() != null) {
                            /**
                             * Shangdu Lin - 20170419
                             * 非货币基金、货币基金：如果净值日期小于当前工作日，则不计算确认日期是当前工作日的基金份额
                             */
                            BigDecimal currentShare = shareModel.getCurrentShare();
                            //计算当日收益
                            BigDecimal oldShares = currentShare;
                            for (ShareDetailQryModel shareDetailQryModel : shareDetailQryFundModels) {
                                //logger.debug("aaaaa 确认日期：{}, 基金编码：{}， 可用份额：{}",shareDetailQryModel.getAffirmDate(),shareDetailQryModel.getFundCode(),shareDetailQryModel.getEnableShares());
                                if (shareModel.getFundCode().equals(shareDetailQryModel.getFundCode()) && shareDetailQryModel.getAffirmDate().equals(DateUtils.formatDate4(new Date())) && shareModel.getTradeAccount().equals(shareDetailQryModel.getTradeAccount())) {
                                    //logger.debug("货币基金  当前份额：{}，确认份额：{},基金Code:{}，基金名称",oldShares,shareDetailQryModel.getEnableShares(),shareModel.getFundCode(),shareModel.getFundName());
                                    oldShares = oldShares.subtract(shareDetailQryModel.getEnableShares());
                                }
                            }
                            if (fundNetValue.getFundTypeCode() == FundConst.FUND_TYPE_CODE_CURRENCY) {
                                // 日收益=当前份额/10000*万份之收益
                                // TODO:有申购时：日收益=当前份额/10000*万份之收益
                                // 有赎回时: 日收益=当前份额/10000*万份之收益
                                // 日收益
                                BigDecimal dailyProfit = fundNetValue.getDailyProfit();
                                if (dailyProfit == null) {
                                    dailyProfit = new BigDecimal(0);
                                    //logger.error("queryShares-getDailyProfit is null for fund code ={}", shareModel.getFundCode());
                                }
                                BigDecimal todayIncome = oldShares.divide(new BigDecimal(10000), 4)
                                    .multiply(dailyProfit);
                                //logger.debug("万分收益：{}，今日收益：{}，当前份额：{}，老份额：{}",dailyProfit,todayIncome,currentShare);
                                BigDecimal totalDividend = new BigDecimal(0);
                                //计算昨日收益的现金分红部分
                                /**
                                 * 昨日收益加上分红
                                 *
                                 */
                                for (DividendModel dividendModel : dividends) {
                                    if ("1".equals(dividendModel.getAutoBuy()) && shareModel.getFundCode().equals(dividendModel.getFundCode()) && dividendModel.getTradeAccount().equals(shareModel.getTradeAccount())) {
                                        if (dividendModel.getDividendDate().equals(DateUtils.formatDate4(DateUtils.addDay(new Date(), -1)))) {
                                            todayIncome = MoneyUtils.add(todayIncome, dividendModel.getDividendBalance());
                                        }
                                    }
                                }
                                todayIncome = todayIncome.setScale(2, BigDecimal.ROUND_HALF_UP);
                                shareModel.setTodayIncome(todayIncome);
                                // 日收益率
                                // 份额明细查询没有这个字段
                                if (shareModel.getWorthValue() != null) {
                                    if (shareModel.getWorthValue().compareTo(new BigDecimal(0)) > 0) {
                                        BigDecimal todayIncomeRate = todayIncome.divide(shareModel.getWorthValue(), 4);
                                        shareModel.setTodayIncomeRate(todayIncomeRate);
                                    } else {
                                        shareModel.setTodayIncomeRate(new BigDecimal(0));
                                    }
                                    // 万份之收益
                                    shareModel.setDailyProfit(dailyProfit);
                                }

                            } else {
                                // 日收益=当前基金份额*（当天净值- 前一个工作日净值）
                                // TODO:有申购时：日收益=当前基金份额*（当天净值- 前一个工作日净值）
                                // 有赎回时: 日收益=当前基金份额*（当天净值 - 前一个工作日净值）
                                // 日收益率
                                BigDecimal todayIncomeRate = fundNetValue.getNvDailyGrowthRate();
                                if (todayIncomeRate == null) {
                                    todayIncomeRate = new BigDecimal(0);
                                    log.error("queryShares-getNvDailyGrowthRate is null for fund code ={}", shareModel.getFundCode());
                                }
                                shareModel.setTodayIncomeRate(todayIncomeRate);
                                // 日收益=当前基金份额*（当天净值- 前一个工作日净值）
                                BigDecimal lastUnitValue = new BigDecimal(0);
                                if (netValues.containsKey(shareModel.getFundCode())) {
                                    lastUnitValue = netValues.get(shareModel.getFundCode());
                                } else {
                                    lastUnitValue = queryService.getLastUnitValue(shareModel.getFundCode(), fundNetValue.getTradingDay());
                                    netValues.put(shareModel.getFundCode(), lastUnitValue);
                                }
                                BigDecimal margin = MoneyUtils.subtract(fundNetValue.getUnitNV(), lastUnitValue);
                                BigDecimal todayIncome = oldShares.multiply(margin);
                                //计算昨日收益的现金分红部分
                                /**
                                 * 昨日收益加上分红
                                 *
                                 */
                                for (DividendModel dividendModel : dividends) {
                                    if ("1".equals(dividendModel.getAutoBuy()) && shareModel.getFundCode().equals(dividendModel.getFundCode()) && dividendModel.getTradeAccount().equals(shareModel.getTradeAccount())) {
                                        if (dividendModel.getDividendDate().equals(DateUtils.formatDate4(DateUtils.addDay(new Date(), -1)))) {
                                            todayIncome = MoneyUtils.add(todayIncome, dividendModel.getDividendBalance());
                                        }
                                    }
                                }
                                todayIncome = todayIncome.setScale(2, BigDecimal.ROUND_HALF_UP);
                                shareModel.setTodayIncome(todayIncome);

                            }
                        }

                        break;
                    }
                }

                // 更新最新的资产值
                // 资产=当前份额*净值
                BigDecimal netValue = shareModel.getNetValue();
                if (netValue == null) {
                    netValue = new BigDecimal(0);
                }
                BigDecimal worthValue = shareModel.getCurrentShare().multiply(netValue);
                worthValue = MoneyUtils.add(worthValue, shareModel.getUnpaidIncome());
                shareModel.setWorthValue(worthValue);
                BigDecimal totalDividend = new BigDecimal(0);

                for (DividendModel dividendModel : dividends) {
                    if ("1".equals(dividendModel.getAutoBuy()) && shareModel.getFundCode().equals(dividendModel.getFundCode()) && dividendModel.getTradeAccount().equals(shareModel.getTradeAccount())) {
                        if (dividendModel.getDividendDate().compareTo(DateUtils.formatDate4(new Date())) < 0) {
                            totalDividend = MoneyUtils.add(totalDividend, dividendModel.getDividendBalance());
                        }
                        if (DateUtils.formatDate4(new Date()).compareTo(dividendModel.getEquityRegDate()) >= 0 && DateUtils.formatDate4(new Date()).compareTo(dividendModel.getDividendDate()) <= 0) {
                            shareModel.setDividends("该基金最近有分红配送");
                        }
                    }
                }
                if (shareModel.getDividends() == null) {
                    shareModel.setDividends("");
                }
//                //累计收益
//                if (incomeModels.size() != 0) {
//                    for (IncomeModel incomeModel : incomeModels) {
//                        if (incomeModel.getFundCode().equals(shareModel.getFundCode())&& incomeModel.getTradeAccount().equals(shareModel.getTradeAccount())) {
//                            shareModel.setTotalAccumIncome(incomeModel.getAccumIncome());
//                            //shareModel.setTotalAccumIncome(MoneyUtils.add(incomeModel.getAccumIncome(), totalDividend));
//                            break;
//                        }
//                    }
//                }

                //累计收益新算法   资产 加 赎回金额 减 申购金额 加上现金分红
                BigDecimal accumIncome = MoneyUtils.add(worthValue, totalDividend);
                for (ConfirmModel confirm : confirms) {
                    if (confirm.getFundCode().equals(shareModel.getFundCode()) && confirm.getTradeAcco().equals(shareModel.getTradeAccount())) {
                        if (confirm.getTAConfirmFlag().equals(GlobalConstant.TACONFIRM_FLAG_CONFIRMED)) {
                            if (confirm.getFundBusinCode().equals(GlobalConstant.FUND_BUSIN_CODE_CONFIRM_BUY) || confirm.getFundBusinCode().equals(GlobalConstant.FUND_BUSIN_CODE_CONFIRM_FIX_BUY)) {
                                accumIncome = MoneyUtils.subtract(accumIncome, confirm.getTradeConfirmBalance());
                            }
                            if (confirm.getFundBusinCode().equals(GlobalConstant.FUND_BUSIN_CODE_CONFIRM_SELL)) {
                                accumIncome = MoneyUtils.add(accumIncome, confirm.getTradeConfirmBalance());
                            }
                        }
                    }
                }

                shareModel.setTotalAccumIncome(accumIncome);
                totalAccumIncome = MoneyUtils.add(totalAccumIncome, accumIncome);
                log.debug("totalAccumIncome1:{}", totalAccumIncome);
                //赎回在途笔数
                Integer sellInTransit = CalculateAssetsUtils.numSellOfInTransit(applys, lookups, false, shareModel.getFundCode(), shareModel.getTradeAccount());
                shareModel.setSellInTransit(sellInTransit);


//                // 计算持仓收益率
//                shareModel.setAccumIncomeRate(new BigDecimal(0));
//                BigDecimal fundWorthValue = shareModel.getWorthValue();
//                if (fundWorthValue != null && fundWorthValue.compareTo(new BigDecimal(0)) > 0) {
//                    // 持仓收益率
//                    BigDecimal accumIncomeRate = shareModel.getShareIncome().divide(fundWorthValue, 4);
//                    shareModel.setAccumIncomeRate(accumIncomeRate);
//                }

                // 获取基金类型
                NewsModel newsModel = queryService.getRiskLevel(shareModel.getFundCode());
                if (newsModel != null) {
                    shareModel.setFundType(newsModel.getFundType());
                    shareModel.setRiskLevel(newsModel.getRiskLevel());
                    shareModel.setRiskLevelString(newsModel.getRiskLevelString());
                }

                SecurityProduct product = fundDetailService.getSecurityProduct(shareModel.getFundCode());

                if (product == null) {
                    result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
                    log.error("Security Product is not exist");
                    result.setErrorCode(ErrorConstant.ERROR_FUND_NOT_EXIST);
                    result.setSuccess(false);
                    return result;
                }

                // 七日年化率
                FundMMYieldPerformance perf = fundMMYieldPerformanceService.getFundMMYieldPerformance(product.getInnerCode());
                if (perf != null && perf.getLatestWeeklyYield() != null) {
                    shareModel.setLatestWeeklyYield(MoneyUtils.formatMoney(perf.getLatestWeeklyYield(), 2));// 最近7日折算年收益率（%）
                } else {
                    shareModel.setLatestWeeklyYield("");
                }

                FundDetail fundDetail = fundDetailDao.queryByFundCode(shareModel.getFundCode());
                if (fundDetail != null && fundDetail.getCarryOverDateRemark() != null) {
                    shareModel.setClearDate(fundDetail.getCarryOverDateRemark());
                } else {
                    shareModel.setClearDate("");
                }

                //totalAccumIncome = totalAccumIncome.add(shareDetailTotalModel.getAccumIncome());
                totalWorthValue = totalWorthValue.add(shareModel.getWorthValue());
                totalTodayIncome = totalTodayIncome.add(shareModel.getTodayIncome());
                //totalAccumIncome = MoneyUtils.add(totalAccumIncome, shareModel.getTotalAccumIncome());
                shareModel.setCanDividend(true);
                if (shareModel.getAppFundType() == 1109 || shareModel.getAppFundType() == 900000) {
                    shareModel.setDividendMethodString("当前基金仅支持红利再投资");
                    shareModel.setCanDividend(false);
                }
            }

            //加上全赎的累计收益
//            for (IncomeModel incomeModel : incomeModelsNormal){
//                if (!fundCodes.contains(incomeModel.getFundCode())){
//                    logger.debug("编码：{}",incomeModel.getFundCode());
//                    totalAccumIncome = MoneyUtils.add(totalAccumIncome, incomeModel.getAccumIncome());
//                }
//            }

            for (ConfirmModel confirm : confirms) {
                if (!confirm.getTradeAcco().startsWith("ZH") && !fundCodes.contains(confirm.getFundCode())) {
                    if (!CalculateAssetsUtils.isT0Fund(lookups, confirm.getFundCode())) {
                        if (confirm.getTAConfirmFlag().equals(GlobalConstant.TACONFIRM_FLAG_CONFIRMED)) {
                            if (confirm.getFundBusinCode().equals(GlobalConstant.FUND_BUSIN_CODE_CONFIRM_BUY) || confirm.getFundBusinCode().equals(GlobalConstant.FUND_BUSIN_CODE_CONFIRM_FIX_BUY)) {
                                totalAccumIncome = MoneyUtils.subtract(totalAccumIncome, confirm.getTradeConfirmBalance());
                            }
                            if (confirm.getFundBusinCode().equals(GlobalConstant.FUND_BUSIN_CODE_CONFIRM_SELL)) {
                                totalAccumIncome = MoneyUtils.add(totalAccumIncome, confirm.getTradeConfirmBalance());
                            }
                        }
                    }
                }
            }
            log.debug("totalAccumIncome2:{}", totalAccumIncome);
            //将全赎部分的分红 加到累计收益中
            BigDecimal totalDividend = new BigDecimal(0);
            for (DividendModel dividendModel : dividends) {
                //现金分红
                if ("1".equals(dividendModel.getAutoBuy())
                    // 没有持仓（全赎）
                    && !fundCodes.contains(dividendModel.getFundCode())
                    //不是 T0基金
                    && !CalculateAssetsUtils.isT0Fund(lookups, dividendModel.getFundCode())
                    // 分红日在今天之前
                    && dividendModel.getDividendDate().compareTo(DateUtils.formatDate4(new Date())) < 0) {
                    totalDividend = MoneyUtils.add(totalDividend, dividendModel.getDividendBalance());
                }
            }
            totalAccumIncome = MoneyUtils.add(totalAccumIncome, totalDividend);
            log.debug("totalAccumIncome3:{}", totalAccumIncome);

//            // 查出这个用户下所有的未确认的交易记录，传ClientId
//            map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
//                user.getExternalClientId(), "", "", "", GlobalConstant.TACONFIRM_FLAG_UNCONFIRM, "", "", "", "", "",
//                "", "", "");
//
//            // 查询结果
//            list = new ArrayList<>();
//            HundsunUtils.ConvertToList(map, list, result);
//            if (!result.getSuccess()) {
//                return result;
//            }
//            // populate applys
//            ApplyListResult applyListResult = new ApplyListResult();
//            List<ApplyModel> applys = ModelPopulateUtils.populateApply(list, applyListResult, null, null);
//            // 把T0基金过滤掉，因为T0基金有专门的页面来显示
//            filterT0(applys, filterT0);
            //总资产=确认的资产+有效在途的金额
            BigDecimal totalInTransit = new BigDecimal(0);
            Integer numInTransit = CalculateAssetsUtils.numOfInTransitWithoutPortfolio(applys, lookups, null);
            totalInTransit = CalculateAssetsUtils.sumOfInTransitWithoutPortfolio(applys, lookups, null);
            totalWorthValue = MoneyUtils.add(totalWorthValue, totalInTransit);

            //将多卡的持有份额合并   并累加份额 资产 等信息
            List<ShareModel> normalSharesNew = new ArrayList<>();
            List<String> fundCodesNew = new ArrayList<>();
            for (ShareModel shareModel : normalShares) {
                if (fundCodesNew.contains(shareModel.getFundCode())) {
                    for (ShareModel shareModelNew : normalSharesNew) {
                        if (shareModel.getFundCode().equals(shareModelNew.getFundCode())) {
                            shareModelNew.setAvailableDueShare(MoneyUtils.add(shareModelNew.getAvailableDueShare(), shareModel.getAvailableDueShare()));
                            shareModelNew.setCost(MoneyUtils.add(shareModelNew.getCost(), shareModel.getCost()));
                            shareModelNew.setCurrentShare(MoneyUtils.add(shareModelNew.getCurrentShare(), shareModel.getCurrentShare()));
                            shareModelNew.setFrozenShare(MoneyUtils.add(shareModelNew.getFrozenShare(), shareModel.getFrozenShare()));
                            shareModelNew.setEnableShares(MoneyUtils.add(shareModelNew.getEnableShares(), shareModel.getEnableShares()));
                            Integer sellIntransit = shareModelNew.getSellInTransit() + shareModel.getSellInTransit();
                            shareModelNew.setSellInTransit(sellIntransit);
                            shareModelNew.setTodayIncome(MoneyUtils.add(shareModelNew.getTodayIncome(), shareModel.getTodayIncome()));
                            shareModelNew.setTotalAccumIncome(MoneyUtils.add(shareModelNew.getTotalAccumIncome(), shareModel.getTotalAccumIncome()));
                            shareModelNew.setWorthValue(MoneyUtils.add(shareModelNew.getWorthValue(), shareModel.getWorthValue()));

                            shareModelNew.getShareDetails().add(shareModel);
                        }
                    }
                } else {
                    List<ShareModel> sharesInside = new ArrayList<>();
                    //因为 如果用原来的模型会导致无限循环  所以要新new一个
                    ShareModel shareModelCopy = new ShareModel();
                    org.springframework.beans.BeanUtils.copyProperties(shareModel, shareModelCopy);
                    shareModelCopy.setShareDetails(sharesInside);
                    shareModelCopy.getShareDetails().add(shareModel);
                    normalSharesNew.add(shareModelCopy);
                    fundCodesNew.add(shareModel.getFundCode());
                }
            }

            List<ShareModel> normalSharesReal = new ArrayList<>();
            for (int i = 1; i <= normalSharesNew.size(); i++) {
                if (i >= beginNum && i < requestNum + beginNum) {
                    normalSharesReal.add(normalSharesNew.get(i - 1));
                }
            }
            result.setSuccess(true);
            //result.setShareDetailTotalModels(normalShares);


            result.setNetValueDate(netValueDate);
            result.setShares(normalSharesReal);
            result.setTotalInTransit(totalInTransit);
            result.setTotalNumInTransit(numInTransit);
            result.setTotalAccumIncome(totalAccumIncome);
            result.setTotalFundBalance(totalFundBalance);
            result.setTotalTodayIncome(totalTodayIncome);
            result.setTotalShareIncome(totalShareIncome);
            result.setTotalWorthValue(totalWorthValue);

            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(log, "queryShares - Exception:", exception);
            throw new SystemDBException("queryShares Failure!", exception);
        }
    }

    /**
     * 从redis中获取 普通基金分红  机构
     *
     * @return
     */
    public List<DividendModel> getOrganDividend(OrganProfile organProfile, List<OrganBank> organBankList) {

        String key = CacheUtil.getKey(UrlConstants.DIVI_QRY, organProfile.getExternalClientId());
        // from cache
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();

        String diviQry = valueOperations.get(key);

        List<DividendModel> dividends = new ArrayList<>();
        if (StringUtil.isNotEmpty(diviQry)) {
            try {
                dividends = JSONArray.parseArray(diviQry, DividendModel.class);
            } catch (Exception e) {
                log.error("fail to parse array", e);
            }
        } else {
            List<Map<String, Object>> listDividend = new ArrayList<>();
            if (organBankList != null) {
                if (organBankList.size() != 0) {
                    for (OrganBank organBank : organBankList) {

                        Map<String, Object> map = dividendsQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", organBank.getExternalTradeAccount(), "", organProfile.getExternalClientId(), "");
                        List<Map<String, Object>> list = new ArrayList<>();
                        AssetsResult result = new AssetsResult();
                        HundsunUtils.ConvertToList(map, list, result);

                        if (!result.getSuccess()) {
                            throw new BaseException(result.getErrorCode(), result.getErrorMessage());
                        }
                        listDividend.addAll(list);
                    }
                }
            }
            // populate
            BaseListResult baseListResult = new BankListResult();
            dividends = ModelPopulateUtils.populateDividend(listDividend, baseListResult);
            valueOperations.set(key, JSONArray.toJSONString(dividends), GlobalConstant.ASSETS_EXPIRED_HOURS_DEFAULT, TimeUnit.MINUTES);

        }
        return dividends;
    }

    /**
     * 机构日收益
     *
     * @param userId
     * @param fundCode
     * @param type
     * @param beginNum
     * @param requestNum
     * @return
     */
    @Override
    public BaseResult getProfit(Long userId, String fundCode, String type, Integer beginNum, Integer requestNum, Long profileId) {
        Date dateTime = new Date();
        List<OrganBank> organBanks = organBankDao.selectUsableByProfileId(profileId);
        switch (type) {
            case GlobalConstant.ALL_TIME:
                dateTime = null;
                break;
            case GlobalConstant.THIS_YEAR:
                //TODO  提到工具类
                Calendar calendar = Calendar.getInstance();
                int currentYear = calendar.get(Calendar.YEAR);
                calendar.clear();
                calendar.set(Calendar.YEAR, currentYear);
                dateTime = calendar.getTime();
                break;
            case GlobalConstant.THREE_MONTH:
                dateTime = DateUtils.addMondth(dateTime, -3);
                break;
            case GlobalConstant.ONE_MONTH:
                dateTime = DateUtils.addMondth(dateTime, -1);
                break;
            case GlobalConstant.ONE_WEEK:
                dateTime = DateUtils.addDay(dateTime, -7);
                break;
            default:
                dateTime = null;
        }
        //
        List<Profit> profits = new ArrayList<>();
        for (OrganBank organBank : organBanks) {
            if (organBank.getAuditStatus() == 1) {
                List<Profit> profitTrades = profitDao.selectProfitByFundCode(Math.toIntExact(userId), organBank.getExternalTradeAccount(), fundCode, dateTime);
                profits.addAll(profitTrades);

            }
        }
        ProfitResult profitResult = new ProfitResult();
        BigDecimal accumIncome = new BigDecimal(0);
        List<Profit> profitsNew = new ArrayList<>();
        Map<String, Profit> map = new HashMap();
        for (Profit profit : profits) {
            //profit.setDateTime(DateUtils.formatDate(DateUtils.stringToDateWithTime(profit.getDateTime())));
            //profit.setDateTime(DateUtils.String8ToDateStr(profit.getDateTime()));
            accumIncome = MoneyUtils.add(accumIncome, profit.getProfitValue());
            if (profit.getProfitValue() != null){
                profit.setProfitValue(profit.getProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
            }
            if (profit.getAccumulateProfitValue() != null){
                profit.setAccumulateProfitValue(profit.getAccumulateProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
            }
        }
        // 将基金按 基金编号和日期累加  不同交易账号累加
        for (Profit profit : profits) {
            String key = profit.getFundCode() + profit.getDateTime();
            if (map.containsKey(key)) {
                map.get(key).setProfitValue(MoneyUtils.add(map.get(key).getProfitValue(), profit.getProfitValue()));
            } else {
                map.put(key, profit);
            }
        }
        for (String key : map.keySet()) {
            profitsNew.add(map.get(key));
        }
        profitResult.setTotalCount(profitsNew.size());
        //按日期倒序排序
        Collections.sort(profitsNew, new Comparator<Profit>() {
            @Override
            public int compare(Profit o1, Profit o2) {
                String o1No = o1.getDateTime(), o2No = o2.getDateTime();
                return 0 - o1No.compareTo(o2No);
            }
        });
        List<Profit> profitsReal = new ArrayList<>();
        for (int i = 1; i <= profits.size(); i++) {
            if (i >= beginNum && i < requestNum + beginNum) {
                profitsReal.add(profits.get(i - 1));
            }
        }
        profitResult.setProfits(profitsReal);
        profitResult.setAccumIncome(accumIncome);
        return profitResult;
    }

//    /**
//     * 机构日收益
//     *
//     * @param userId
//     * @param fundCode
//     * @param type
//     * @param beginNum
//     * @param requestNum
//     * @return
//     */
//    @Override
//    public BaseResult getProfit(Long userId, String fundCode, String type, Integer beginNum, Integer requestNum, Long profileId) {
//        Date dateTime = new Date();
//        List<OrganBank> organBanks = organBankDao.selectUsableByProfileId(profileId);
//        switch (type) {
//            case GlobalConstant.ALL_TIME:
//                dateTime = null;
//                break;
//            case GlobalConstant.THIS_YEAR:
//                //TODO  提到工具类
//                Calendar calendar = Calendar.getInstance();
//                int currentYear = calendar.get(Calendar.YEAR);
//                calendar.clear();
//                calendar.set(Calendar.YEAR, currentYear);
//                dateTime = calendar.getTime();
//                break;
//            case GlobalConstant.THREE_MONTH:
//                dateTime = DateUtils.addMondth(dateTime, -3);
//                break;
//            case GlobalConstant.ONE_MONTH:
//                dateTime = DateUtils.addMondth(dateTime, -1);
//                break;
//            case GlobalConstant.ONE_WEEK:
//                dateTime = DateUtils.addDay(dateTime, -7);
//                break;
//            default:
//                dateTime = null;
//        }
//        //
//        Date queryTime = assetsIncomeService.getBeginDate(dateTime);
//        List<Profit> profits = new ArrayList<>();
//        for (OrganBank organBank : organBanks) {
//            if (organBank.getAuditStatus() == 1) {
//                List<Profit> profitTrades = profitDao.selectProfitByFundCode(Math.toIntExact(userId), organBank.getExternalTradeAccount(), fundCode, null);
//                profits.addAll(profitTrades);
//
//            }
//        }
//        ProfitResult profitResult = new ProfitResult();
//        BigDecimal accumIncome = new BigDecimal(0);
//        BigDecimal allProfit = new BigDecimal(0);
//        List<Profit> profitsNew = new ArrayList<>();
//        Map<String, Profit> map = new HashMap();
//
//        // 将基金按 基金编号和日期累加  不同交易账号累加
//        for (Profit profit : profits){
//            profit.setDateTime(DateUtils.formatDate(DateUtils.stringToDateWithTime(profit.getDateTime())));
//            String key = profit.getFundCode() + profit.getDateTime();
//            if (map.containsKey(key)){
//                map.get(key).setProfitValue(MoneyUtils.add(map.get(key).getProfitValue(),profit.getProfitValue()));
//                map.get(key).setAccumulateProfitValue(MoneyUtils.add(map.get(key).getAccumulateProfitValue(),profit.getAccumulateProfitValue()));
//            }else {
//                map.put(key,profit);
//            }
//        }
//        for (String key : map.keySet()){
//            profitsNew.add(map.get(key));
//        }
//
//
//        //按日期倒序排序
//        Collections.sort(profitsNew, new Comparator<Profit>() {
//            @Override
//            public int compare(Profit o1, Profit o2) {
//                String o1No = o1.getDateTime(), o2No = o2.getDateTime();
//                return 0 - o1No.compareTo(o2No);
//            }
//        });
//
//
//
//        //这里  为了算  一段时间的累计收益 才搞得这么麻烦
//        List<Profit> profitsByTime = new ArrayList<>();
//        for (Profit profit : profitsNew) {
//            if (profit.getDateTime().compareTo(DateUtils.formatDateTime(queryTime)) > 0){
//                //累加 指定日期后 的 收益
//                allProfit = MoneyUtils.add(allProfit,profit.getProfitValue());
//                if (profit.getProfitValue() != null){
//                    profit.setProfitValue(profit.getProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
//                }
//                if (profit.getAccumulateProfitValue() != null){
//                    profit.setAccumulateProfitValue(profit.getAccumulateProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
//                }
//                profitsByTime.add(profit);
//            }
//        }
//        profitResult.setTotalCount(profitsByTime.size());
//
//        //如果  查到了  指定查询日期 中  所有日期 的 收益   就可以 通过累加 日收益 获取 当前区间的累计收益
//        //如果  没有查到所有   则不能累加  需要取总收益     因为不取的话 累加会 少加一个 初始的 累计收益
//        if (profitsNew.isEmpty()){
//            accumIncome = allProfit;
//        }else if (dateTime == null || profitsNew.get(profitsNew.size() - 1).getDateTime().compareTo(DateUtils.formatDate(dateTime)) > 0){
//            accumIncome = profitsNew.get(0).getAccumulateProfitValue();
//        }else {
//            accumIncome = allProfit;
//        }
//
//
//        List<Profit> profitsReal = new ArrayList<>();
//        for (int i = 1; i <= profitsByTime.size(); i++) {
//            if (i >= beginNum && i < requestNum + beginNum) {
//                profitsReal.add(profitsByTime.get(i - 1));
//            }
//        }
//        profitResult.setProfits(profitsReal);
//        profitResult.setAccumIncome(accumIncome);
//        return profitResult;
//    }

    @Override
    public BaseResult getAccum(Long userId, String fundCode, String type, Long profileId) {
        Date dateTime = new Date();
        List<OrganBank> organBanks = organBankDao.selectUsableByProfileId(profileId);
        switch (type) {
            case GlobalConstant.ALL:
                dateTime = null;
                break;
            case GlobalConstant.YEAR:
                dateTime = DateUtils.addMondth(dateTime, -12);
                break;
            case GlobalConstant.HALF_YEAR:
                dateTime = DateUtils.addMondth(dateTime, -6);
                break;
            case GlobalConstant.SEASON:
                dateTime = DateUtils.addMondth(dateTime, -3);
                break;
            case GlobalConstant.MONTH:
                dateTime = DateUtils.addMondth(dateTime, -1);
                break;
            default:
                dateTime = null;
        }
        //
        List<Profit> profits = new ArrayList<>();
        for (OrganBank organBank : organBanks) {
            if (organBank.getAuditStatus() == 1) {
                List<Profit> profitTrades = profitDao.selectAccumulateByFundCode(Math.toIntExact(userId), organBank.getExternalTradeAccount(), fundCode, dateTime);
                profits.addAll(profitTrades);
            }
        }
        List<Profit> profitsNew = new ArrayList<>();
        Map<String, Profit> map = new HashMap();
        for (Profit profit : profits) {
            if (profit.getProfitValue() != null){
                profit.setProfitValue(profit.getProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
            }
            if (profit.getAccumulateProfitValue() != null){
                profit.setAccumulateProfitValue(profit.getAccumulateProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
            }
            //profit.setDateTime(DateUtils.formatDate(DateUtils.stringToDateWithTime(profit.getDateTime())));
        }
        // 将基金按 基金编号和日期累加  不同交易账号累加
        for (Profit profit : profits) {
            String key = profit.getFundCode() + profit.getDateTime();
            if (map.containsKey(key)) {
                map.get(key).setAccumulateProfitValue(MoneyUtils.add(map.get(key).getAccumulateProfitValue(), profit.getAccumulateProfitValue()));
                map.get(key).setProfitValue(MoneyUtils.add(map.get(key).getProfitValue(), profit.getProfitValue()));
            } else {
                map.put(key, profit);
            }
        }
        for (String key : map.keySet()) {
            profitsNew.add(map.get(key));
        }
        //按日期正序排序
        Collections.sort(profitsNew, new Comparator<Profit>() {
            @Override
            public int compare(Profit o1, Profit o2) {
                String o1No = o1.getDateTime(), o2No = o2.getDateTime();
                return o1No.compareTo(o2No);
            }
        });
        BaseResult result = new BaseResult();
        result.setResult(profitsNew);
        return result;
    }

    /**
     * 单个 基金的资产详情
     * @param userId
     * @param fundCode
     * @return
     * @throws BaseException
     */
    @Override
    public BaseResult queryOrganFundShares(Long userId, String fundCode, Long profileId) throws BaseException {
        log.info("queryShares - userId=" + userId);

        BaseResult result = new BaseResult();
        try {
            // Step 1: 获取用户
            //User user = userDao.getEntity(userId);

            List<OrganBank> organBankList = organBankDao.selectUsableByProfileId(profileId);

            OrganProfile organProfile = organProfileService.getById(profileId);

            // 判断是否已开户
            if (organProfile == null || StringUtil.isEmpty(organProfile.getExternalClientId())) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
                return result;
            }


            // 根据恒生银行编号获取银行名称
            List<Lookup> lookupsBank = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);




            // Step 2: 资产查询, 查询该用户下的所有份额
            Map<String, ShareModel> shareMap = new HashMap<>();
            List<ShareModel> normalShares = new ArrayList<>();
            //分红
            List<DividendModel> dividends = getOrganDividend(organProfile, organBankList);
            //收益
            //List<IncomeModel> incomeModels = getIncome(user,userBankList);
            List<Map<String, Object>> list = new ArrayList<>();
            if (organBankList != null) {
                if (organBankList.size() != 0) {
                    List<Map<String, Object>> listAll = new ArrayList<>();

                    for (OrganBank organBank : organBankList) {
                        // 查询该用户下的所有非组合基金份额
                        Map<String, Object> map = shareQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, organBank.getExternalTradeAccount(), "1", "", fundCode, "",
                            organProfile.getExternalClientId(), "", "", null);
                        list = new ArrayList<>();
                        HundsunUtils.ConvertToList(map, list, result);
                        if (!result.getSuccess()) {
                            return result;
                        }
                        listAll.addAll(list);
                    }
                    normalShares = ModelPopulateUtils.populateNormalShare(listAll, lookupsBank);
                }
            }
//
            //份额明细
            ShareDetailQryDto shareDetailQryDto = ShareDetailQryDto.builder()
                .qry_beginrownum("1")
                .begin_date(DateUtils.formatDate4(new Date()))
                .client_id(organProfile.getExternalClientId())
                .end_date(DateUtils.formatDate4(new Date()))
                .reqry_recordsum_flag("1")
                .request_num(GlobalConstant.MAX_REQUEST_NUM)
                .sort_direction("1")
                .fund_code(fundCode)
                .build();
            Map<String, Object> map = hsShareDetailQryService.query(shareDetailQryDto);
            list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }

            //普通基金
            List<ShareDetailQryModel> shareDetailQryFundModels = new ArrayList<>();
            if (organBankList != null) {
                if (organBankList.size() != 0) {
                    for (OrganBank organBank : organBankList) {
                        shareDetailQryFundModels = ModelPopulateUtils.populateOrganShareDetailQryFund(list, organBank);
                    }
                }
            }

//            // 把T0基金过滤掉，因为T0基金有专门的页面来显示
//            if (filterT0) {
//                List<Lookup> T0Funds = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
//                Iterator<ShareModel> iterator = normalShares.iterator();
//                while (iterator.hasNext()) {
//                    ShareModel model = iterator.next();
//                    if (ModelPopulateUtils.isT0Fund(T0Funds, model.getFundCode())) {
//                        iterator.remove();
//                    }
//                }
//            }

            // Step 3: 从聚源获取基金信息
            List<String> fundCodeList = new ArrayList<String>();
            for (ShareModel shareModel : normalShares) {
                fundCodeList.add(shareModel.getFundCode());
            }

            List<FundNetValueResult> fundNetValueList = null;
            try {
                Date t = queryService.maxDate();
                fundNetValueList = fundDetailService.getFundNetValueByBatch(fundCodeList, DateUtils.addDay(new Date(), -1));
            } catch (Exception ex) {
                ExceptionUtil.logError(log, "queryShares - fundDetailService - Exception:", ex);
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_SYSTEM);
                result.setErrorCode(ErrorConstant.ERROR_GILDATA_WRONG);
                return result;
            }

            // 如果没有找到聚源的，则默认为空
            if (fundNetValueList == null) {
                fundNetValueList = new ArrayList<>();
            }

            // Step 4: 从恒生获取交易确认信息
            // 入参为交易账号的话，只查询该交易账号下的交易, 如果为客户编号的话，则查询该客户编号下的所有交易账号的交易
            Map<String, Object> confirmMap = tradeConfirmQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1",
                organProfile.getExternalClientId(), "", "");

            // 查询结果
            List<Map<String, Object>> mapList = new ArrayList<>();
            HundsunUtils.ConvertToList(confirmMap, mapList, result);
            if (!result.getSuccess()) {
                return result;
            }


            // populate
            List<ConfirmModel> confirms = ModelPopulateUtils.populateConfirm(mapList);



            /**
             * 交易记录
             */
            // 查出这个用户下所有的未确认的交易记录，传ClientId
            map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
                organProfile.getExternalClientId(), "", "", "", GlobalConstant.TACONFIRM_FLAG_UNCONFIRM, "", "", "", "", "",
                "", "", "");

            // 查询结果
            list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return result;
            }
            // populate applys
            ApplyListResult applyListResult = new ApplyListResult();
            List<ApplyModel> applys = ModelPopulateUtils.populateApply(list, applyListResult, null, null);
            // 把T0基金过滤掉，因为T0基金有专门的页面来显示

            // Step 5: 根据数据计算
            // 总持仓收益
            BigDecimal totalAccumIncome = new BigDecimal(0);
            log.debug("totalAccumIncome1:{}",totalAccumIncome);

            // 总本金
            BigDecimal totalFundBalance = new BigDecimal(0);
            // 总资产
            BigDecimal totalWorthValue = new BigDecimal(0);
            // 总当日收益
            BigDecimal totalTodayIncome = new BigDecimal(0);
            //总持仓收益
            BigDecimal totalShareIncome = new BigDecimal(0);
            // 保存上一工作日净值
            Map<String, BigDecimal> netValues = new HashedMap();
            // 净值日期
            Date netValueDate = DateUtils.addDay(new Date(), -1); //默认净值日期为前一天

            //基金编码集合
            List<String> fundCodes = new ArrayList<>();

            for (ShareModel shareModel : normalShares) {
                if (StringUtils.isNotBlank(fundCode)){
                    if(!fundCode.equals(shareModel.getFundCode())){
                        continue;
                    }
                }
                FundModel fundModel = queryService.queryFund(shareModel.getFundCode());
                shareModel.setFundStatus(fundModel.getFundStatus());
                fundCodes.add(shareModel.getFundCode());
                List<OrganBank> organBanks = organBankDao.selectByTradeAccount(shareModel.getTradeAccount());
                OrganBank userBankForBranch = new OrganBank();
                if (organBanks != null && !organBanks.isEmpty()) {
                    userBankForBranch = organBanks.get(0);
                    shareModel.setBranchBank(userBankForBranch.getUbBranchbank() == null ? "" : userBankForBranch.getUbBranchbank());
                    shareModel.setBranchBankName(userBankForBranch.getUbBankBranchName() == null ? "" : userBankForBranch.getUbBankBranchName());
                }

                // 更新基金
                // 设置净值默认值
                shareModel.setNetValue(new BigDecimal(0));
                // 设置今日收益默认值
                shareModel.setTodayIncome(new BigDecimal(0));
                // 设置今日收益率默认值
                shareModel.setTodayIncomeRate(new BigDecimal(0));
                // 设置基金信息
                for (FundNetValueResult fundNetValue : fundNetValueList) {
                    // 聚源没有找到该只基金
                    if (fundNetValue == null || StringUtil.isEmpty(fundNetValue.getFundCode()) || fundNetValue.getFundTypeCode() == null) {
                        continue;
                    }
                    // 以聚源的数据为准
                    if (fundNetValue.getFundCode().equals(shareModel.getFundCode())) {
                        shareModel.setFundName(fundNetValue.getChiNameAbbr());
                        shareModel.setNetValue(fundNetValue.getUnitNV());
                        shareModel.setNetValueDate(fundNetValue.getTradingDay());
                        netValueDate = fundNetValue.getTradingDay();
                        // 设置前端显示的基金类型
                        shareModel.setAppFundType(fundNetValue.getFundTypeCode());
                        if (fundNetValue.getFundTypeCode() != null) {
                            /**
                             * Shangdu Lin - 20170419
                             * 非货币基金、货币基金：如果净值日期小于当前工作日，则不计算确认日期是当前工作日的基金份额
                             */
                            BigDecimal currentShare = shareModel.getCurrentShare();
                            //计算当日收益
                            BigDecimal oldShares = currentShare;
                            for (ShareDetailQryModel shareDetailQryModel : shareDetailQryFundModels) {
                                //logger.debug("aaaaa 确认日期：{}, 基金编码：{}， 可用份额：{}",shareDetailQryModel.getAffirmDate(),shareDetailQryModel.getFundCode(),shareDetailQryModel.getEnableShares());
                                if (shareModel.getFundCode().equals(shareDetailQryModel.getFundCode()) && shareDetailQryModel.getAffirmDate().equals(DateUtils.formatDate4(new Date())) && shareModel.getTradeAccount().equals(shareDetailQryModel.getTradeAccount())) {
                                    //logger.debug("货币基金  当前份额：{}，确认份额：{},基金Code:{}，基金名称",oldShares,shareDetailQryModel.getEnableShares(),shareModel.getFundCode(),shareModel.getFundName());
                                    oldShares = oldShares.subtract(shareDetailQryModel.getEnableShares());
                                }
                            }
                            if (fundNetValue.getFundTypeCode() == FundConst.FUND_TYPE_CODE_CURRENCY) {
                                // 日收益=当前份额/10000*万份之收益
                                // TODO:有申购时：日收益=当前份额/10000*万份之收益
                                // 有赎回时: 日收益=当前份额/10000*万份之收益
                                // 日收益
                                BigDecimal dailyProfit = fundNetValue.getDailyProfit();
                                if (dailyProfit == null) {
                                    dailyProfit = new BigDecimal(0);
                                    //logger.error("queryShares-getDailyProfit is null for fund code ={}", shareModel.getFundCode());
                                }
                                BigDecimal todayIncome = oldShares.divide(new BigDecimal(10000), 4)
                                    .multiply(dailyProfit);
                                //logger.debug("万分收益：{}，今日收益：{}，当前份额：{}，老份额：{}",dailyProfit,todayIncome,currentShare);
                                BigDecimal totalDividend = new BigDecimal(0);
                                //计算昨日收益的现金分红部分
                                /**
                                 * 昨日收益加上分红
                                 *
                                 */
                                for (DividendModel dividendModel : dividends) {
                                    if ("1".equals(dividendModel.getAutoBuy()) && shareModel.getFundCode().equals(dividendModel.getFundCode())&& dividendModel.getTradeAccount().equals(shareModel.getTradeAccount())) {
                                        if (dividendModel.getDividendDate().equals(DateUtils.formatDate4(DateUtils.addDay(new Date(), -1)))) {
                                            todayIncome = MoneyUtils.add(todayIncome, dividendModel.getDividendBalance());
                                        }
                                    }
                                }
                                todayIncome = todayIncome.setScale(2, BigDecimal.ROUND_HALF_UP);
                                shareModel.setTodayIncome(todayIncome);
                                // 日收益率
                                // 份额明细查询没有这个字段
                                if (shareModel.getWorthValue() != null) {
                                    if (shareModel.getWorthValue().compareTo(new BigDecimal(0)) > 0) {
                                        BigDecimal todayIncomeRate = todayIncome.divide(shareModel.getWorthValue(), 4);
                                        shareModel.setTodayIncomeRate(todayIncomeRate);
                                    } else {
                                        shareModel.setTodayIncomeRate(new BigDecimal(0));
                                    }
                                    // 万份之收益
                                    shareModel.setDailyProfit(dailyProfit);
                                }

                            } else {
                                // 日收益=当前基金份额*（当天净值- 前一个工作日净值）
                                // TODO:有申购时：日收益=当前基金份额*（当天净值- 前一个工作日净值）
                                // 有赎回时: 日收益=当前基金份额*（当天净值 - 前一个工作日净值）
                                // 日收益率
                                BigDecimal todayIncomeRate = fundNetValue.getNvDailyGrowthRate();
                                if (todayIncomeRate == null) {
                                    todayIncomeRate = new BigDecimal(0);
                                    log.error("queryShares-getNvDailyGrowthRate is null for fund code ={}", shareModel.getFundCode());
                                }
                                shareModel.setTodayIncomeRate(todayIncomeRate);
                                // 日收益=当前基金份额*（当天净值- 前一个工作日净值）
                                BigDecimal lastUnitValue = new BigDecimal(0);
                                if (netValues.containsKey(shareModel.getFundCode())) {
                                    lastUnitValue = netValues.get(shareModel.getFundCode());
                                } else {
                                    lastUnitValue = queryService.getLastUnitValue(shareModel.getFundCode(), fundNetValue.getTradingDay());
                                    netValues.put(shareModel.getFundCode(), lastUnitValue);
                                }
                                BigDecimal margin = MoneyUtils.subtract(fundNetValue.getUnitNV(), lastUnitValue);
                                BigDecimal todayIncome = oldShares.multiply(margin);
                                //计算昨日收益的现金分红部分
                                /**
                                 * 昨日收益加上分红
                                 *
                                 */
                                for (DividendModel dividendModel : dividends) {
                                    if ("1".equals(dividendModel.getAutoBuy()) && shareModel.getFundCode().equals(dividendModel.getFundCode())&& dividendModel.getTradeAccount().equals(shareModel.getTradeAccount())) {
                                        if (dividendModel.getDividendDate().equals(DateUtils.formatDate4(DateUtils.addDay(new Date(), -1)))) {
                                            todayIncome = MoneyUtils.add(todayIncome, dividendModel.getDividendBalance());
                                        }
                                    }
                                }
                                todayIncome = todayIncome.setScale(2, BigDecimal.ROUND_HALF_UP);
                                shareModel.setTodayIncome(todayIncome);

                            }
                        }

                        break;
                    }
                }

                // 更新最新的资产值
                // 资产=当前份额*净值
                BigDecimal netValue = shareModel.getNetValue();
                if (netValue == null) {
                    netValue = new BigDecimal(0);
                }
                BigDecimal worthValue = shareModel.getCurrentShare().multiply(netValue);
                worthValue = MoneyUtils.add(worthValue, shareModel.getUnpaidIncome());
                shareModel.setWorthValue(worthValue);
                BigDecimal totalDividend = new BigDecimal(0);

                for (DividendModel dividendModel : dividends) {
                    if ("1".equals(dividendModel.getAutoBuy()) && shareModel.getFundCode().equals(dividendModel.getFundCode())&& dividendModel.getTradeAccount().equals(shareModel.getTradeAccount())) {
                        if (dividendModel.getDividendDate().compareTo(DateUtils.formatDate4(new Date())) < 0) {
                            totalDividend = MoneyUtils.add(totalDividend, dividendModel.getDividendBalance());
                        }
                        if (DateUtils.formatDate4(new Date()).compareTo(dividendModel.getEquityRegDate()) >= 0 && DateUtils.formatDate4(new Date()).compareTo(dividendModel.getDividendDate()) <= 0) {
                            shareModel.setDividends("该基金最近有分红配送");
                        }
                    }
                }
                if (shareModel.getDividends() == null) {
                    shareModel.setDividends("");
                }
//                //累计收益
//                if (incomeModels.size() != 0) {
//                    for (IncomeModel incomeModel : incomeModels) {
//                        if (incomeModel.getFundCode().equals(shareModel.getFundCode())&& incomeModel.getTradeAccount().equals(shareModel.getTradeAccount())) {
//                            shareModel.setTotalAccumIncome(incomeModel.getAccumIncome());
//                            //shareModel.setTotalAccumIncome(MoneyUtils.add(incomeModel.getAccumIncome(), totalDividend));
//                            break;
//                        }
//                    }
//                }

                //累计收益新算法   资产 加 赎回金额 减 申购金额 加上现金分红
                BigDecimal accumIncome = MoneyUtils.add(worthValue, totalDividend);
                for (ConfirmModel confirm :  confirms){
                    if (confirm.getFundCode().equals(shareModel.getFundCode()) && confirm.getTradeAcco().equals(shareModel.getTradeAccount())){
                        if (confirm.getTAConfirmFlag().equals(GlobalConstant.TACONFIRM_FLAG_CONFIRMED)){
                            if (confirm.getFundBusinCode().equals(GlobalConstant.FUND_BUSIN_CODE_CONFIRM_BUY) || confirm.getFundBusinCode().equals(GlobalConstant.FUND_BUSIN_CODE_CONFIRM_FIX_BUY)){
                                accumIncome = MoneyUtils.subtract(accumIncome, confirm.getTradeConfirmBalance());
                            }
                            if (confirm.getFundBusinCode().equals(GlobalConstant.FUND_BUSIN_CODE_CONFIRM_SELL)){
                                accumIncome = MoneyUtils.add(accumIncome, confirm.getTradeConfirmBalance());
                            }
                        }
                    }
                }

                shareModel.setTotalAccumIncome(accumIncome);
                totalAccumIncome = MoneyUtils.add(totalAccumIncome, accumIncome);
                log.debug("totalAccumIncome1:{}",totalAccumIncome);
                //赎回在途笔数
                Integer sellInTransit = CalculateAssetsUtils.organNumSellOfInTransit(applys, shareModel.getFundCode(), shareModel.getTradeAccount());
                shareModel.setSellInTransit(sellInTransit);


//                // 计算持仓收益率
//                shareModel.setAccumIncomeRate(new BigDecimal(0));
//                BigDecimal fundWorthValue = shareModel.getWorthValue();
//                if (fundWorthValue != null && fundWorthValue.compareTo(new BigDecimal(0)) > 0) {
//                    // 持仓收益率
//                    BigDecimal accumIncomeRate = shareModel.getShareIncome().divide(fundWorthValue, 4);
//                    shareModel.setAccumIncomeRate(accumIncomeRate);
//                }

                // 获取基金类型
                NewsModel newsModel = queryService.getRiskLevel(shareModel.getFundCode());
                if (newsModel != null) {
                    shareModel.setFundType(newsModel.getFundType());
                    shareModel.setRiskLevel(newsModel.getRiskLevel());
                    shareModel.setRiskLevelString(newsModel.getRiskLevelString());
                }

                SecurityProduct product = fundDetailService.getSecurityProduct(shareModel.getFundCode());

                if (product == null) {
                    log.error("Security Product is not exist");
                    result.setErrorCode(ErrorConstant.ERROR_FUND_NOT_EXIST);
                    result.setSuccess(false);
                    result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
                    return result;
                }

                // 七日年化率
                FundMMYieldPerformance perf = fundMMYieldPerformanceService.getFundMMYieldPerformance(product.getInnerCode());
                if (perf != null && perf.getLatestWeeklyYield() != null ){
                    shareModel.setLatestWeeklyYield(MoneyUtils.formatMoney(perf.getLatestWeeklyYield(), 2));// 最近7日折算年收益率（%）
                }else{
                    shareModel.setLatestWeeklyYield("");
                }

                FundDetail fundDetail = fundDetailDao.queryByFundCode(shareModel.getFundCode());
                if (fundDetail != null && fundDetail.getCarryOverDateRemark()!=null){
                    shareModel.setClearDate(fundDetail.getCarryOverDateRemark());
                }else {
                    shareModel.setClearDate("");
                }

                //totalAccumIncome = totalAccumIncome.add(shareDetailTotalModel.getAccumIncome());
                totalWorthValue = totalWorthValue.add(shareModel.getWorthValue());
                totalTodayIncome = totalTodayIncome.add(shareModel.getTodayIncome());
                //totalAccumIncome = MoneyUtils.add(totalAccumIncome, shareModel.getTotalAccumIncome());
                shareModel.setCanDividend(true);
                if (shareModel.getAppFundType() == 1109 || shareModel.getAppFundType() == 900000){
                    shareModel.setCanDividend(false);
                }else {
                    List<FundCombinationMapping> funds = fundCombinationMappingDao.selectAll();
                    if (!funds.isEmpty()){
                        for (FundCombinationMapping fund : funds){
                            if (shareModel.getFundCode().equals(fund.getFundCode())){
                                shareModel.setCanDividend(false);
                            }
                        }
                    }
                }
            }

            //加上全赎的累计收益
//            for (IncomeModel incomeModel : incomeModelsNormal){
//                if (!fundCodes.contains(incomeModel.getFundCode())){
//                    logger.debug("编码：{}",incomeModel.getFundCode());
//                    totalAccumIncome = MoneyUtils.add(totalAccumIncome, incomeModel.getAccumIncome());
//                }
//            }


            //将多卡的持有份额合并   并累加份额 资产 等信息
            List<ShareModel> normalSharesNew = new ArrayList<>();
            List<String> fundCodesNew = new ArrayList<>();
            for (ShareModel shareModel : normalShares){
                if (fundCodesNew.contains(shareModel.getFundCode())){
                    for (ShareModel shareModelNew : normalSharesNew){
                        if (shareModel.getFundCode().equals(shareModelNew.getFundCode())){
                            shareModelNew.setAvailableDueShare(MoneyUtils.add(shareModelNew.getAvailableDueShare(),shareModel.getAvailableDueShare()));
                            shareModelNew.setCurrentShare(MoneyUtils.add(shareModelNew.getCurrentShare(),shareModel.getCurrentShare()));
                            shareModelNew.setCost(MoneyUtils.add(shareModelNew.getCost(),shareModel.getCost()));
                            shareModelNew.setEnableShares(MoneyUtils.add(shareModelNew.getEnableShares(),shareModel.getEnableShares()));
                            shareModelNew.setFrozenShare(MoneyUtils.add(shareModelNew.getFrozenShare(),shareModel.getFrozenShare()));
                            Integer sellIntransit = shareModelNew.getSellInTransit() + shareModel.getSellInTransit();
                            shareModelNew.setSellInTransit(sellIntransit);
                            shareModelNew.setTodayIncome(MoneyUtils.add(shareModelNew.getTodayIncome(),shareModel.getTodayIncome()));
                            shareModelNew.setTotalAccumIncome(MoneyUtils.add(shareModelNew.getTotalAccumIncome(),shareModel.getTotalAccumIncome()));
                            shareModelNew.setWorthValue(MoneyUtils.add(shareModelNew.getWorthValue(),shareModel.getWorthValue()));

                            shareModelNew.getShareDetails().add(shareModel);
                        }
                    }
                }else {
                    if (StringUtils.isNotBlank(fundCode)){
                        if(!fundCode.equals(shareModel.getFundCode())){
                            continue;
                        }
                    }
                    List<ShareModel> sharesInside = new ArrayList<>();
                    //因为 如果用原来的模型会导致无限循环  所以要新new一个
                    ShareModel shareModelCopy = new ShareModel();
                    org.springframework.beans.BeanUtils.copyProperties(shareModel,shareModelCopy);
                    shareModelCopy.setShareDetails(sharesInside);
                    shareModelCopy.getShareDetails().add(shareModel);
                    normalSharesNew.add(shareModelCopy);
                    fundCodesNew.add(shareModel.getFundCode());
                }
            }

            result.setSuccess(true);
            result.setResult(normalSharesNew);

            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(log, "queryShares - Exception:", exception);
            throw new SystemDBException("queryShares Failure!", exception);
        }
    }


}
